#include "TextureManager.hpp"
#include "TextureObject.hpp"
#include "HDRManager.hpp"
#include "HDRImageObject.hpp"
#include <iostream>

using namespace std;

//! Setting values for static variables.
TextureManager*    TextureManager::m_pInstance = 0;

bool TextureManager::createInstance()
{
	bool bSuccess = true;

	if(!m_pInstance)
	{
		m_pInstance = new TextureManager;

		if(!m_pInstance)
			bSuccess = false;

		return bSuccess;
	}

	return bSuccess;
}

void TextureManager::destroyInstance()
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = NULL;
	}
}

TextureManager* TextureManager::getInstance()
{
	return m_pInstance;
}

bool TextureManager::isAlreadyLoaded(const string &fileName)
{
	map<string, TextureObject*>::const_iterator filePosition;

	filePosition = m_texMap.find(fileName);

	if(filePosition == m_texMap.end())
		return false;

	return true;
}

bool TextureManager::loadTexture(string fileName, TexType eTextureType)
{
	bool bSuccess = false;

	if(!isAlreadyLoaded(fileName))
	{
		//! If texture specified by filename isn't already in memory than load it.
		TextureObject* pNewTexture = new TextureObject(fileName, eTextureType);

		if(!pNewTexture)
			return bSuccess;

		m_texMap.insert(make_pair(fileName, pNewTexture));
		pNewTexture->IncreaseCounter();
	}
	else
	{
		typedef map<string, TextureObject*>::const_iterator texMapConstIt;
		
		texMapConstIt element = m_texMap.find(fileName);
		TextureObject* pTex = element->second;

		//! If texture is already loaded increase it's reference counter.
		pTex->IncreaseCounter();
	}

	bSuccess = true;
	return bSuccess;
}

bool TextureManager::loadTexture(const HDRImageObject* pHDR)
{
	bool bSuccess = false;

	string objName = HDRManager::getInstance()->getObjectName(pHDR);

	if(!isAlreadyLoaded(objName))
	{
		TextureObject* pNewTexture = new TextureObject(pHDR->getToneMappedBitmap());

		if(!pNewTexture)
			return bSuccess;

		m_texMap.insert(make_pair(objName, pNewTexture));
		pNewTexture->IncreaseCounter();
	}
	else
	{
		typedef map<string, TextureObject*>::const_iterator texMapConstIt;

		texMapConstIt element = m_texMap.find(objName);
		TextureObject* pTex = element->second;
		pTex->IncreaseCounter();
	}

	bSuccess = true;
	return bSuccess;
}

bool TextureManager::unloadTexture(string fileName)
{
	map<string, TextureObject*>::const_iterator ptr = m_texMap.find(fileName);
	TextureObject* pTex = (TextureObject*)ptr->second;

	//! If there are at least two references to this texture - decrease counter.
	if(pTex->GetCounter() > 1)
		pTex->DecreaseCounter();
	else
	{
	//! If this is last reference to texture - delete TextureObject and erase this texture from map.
		delete pTex;
		m_texMap[ fileName ] = NULL;

		m_texMap.erase( ptr );
	}

	return true;
}

const TextureObject* TextureManager::getTexture(string fileName) const
{
	return (m_texMap.find(fileName))->second;
}
